package com.seari.ats.handler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;

import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.slf4j.LoggerFactory;

import redis.clients.jedis.Client;
import redis.clients.jedis.Jedis;

import com.seari.bean.ats.CiosAtsBasInfo;
import com.seari.bean.ats.CiosAtsFasInfo;
import com.seari.bean.ats.CiosAtsHelper;
import com.seari.bean.ats.CiosAtsScadaInfo;
import com.seari.commonutils.redis.JedisUtilProxy;
import com.seari.utils.DataUtil;
import com.seari.utils.GuavaCacheUtil;
import com.seari.utils.PropertiesUtil;

public class AtsSenderRunnable implements Runnable{
	// 日志
	protected static org.slf4j.Logger logger = LoggerFactory
			.getLogger(AtsSenderRunnable.class);

	// Fas List
	private static List<CiosAtsFasInfo> fasList = null;
	// Scada List
	private static List<CiosAtsScadaInfo> scadaList = null;
	// Bas List
	private static List<CiosAtsBasInfo> basList = null;

	// guava list
	private static List<CiosAtsFasInfo> guavaFas = null;
	private static List<CiosAtsScadaInfo> guavaScada = null;
	private static List<CiosAtsBasInfo> guavaBas = null;

	static PropertiesUtil prop = null;

	static List<Object> BasIdList = null;

	static Properties properties = null;

	static {
		try {
			// 创建文件解析
			prop = new PropertiesUtil();
			prop.load(new InputStreamReader(Client.class.getClassLoader()
					.getResourceAsStream("sendBas.properties"), "UTF-8"));
			properties = PropertiesUtil.loadConfig("redisAddress.properties");

			// 启动时加载配置文件读取配置信息
			BasIdList = prop.getKeyList();
		} catch (Exception e) {
			logger.info("Failed to load configuration file !");
		}
	}

	Channel channel;

	public AtsSenderRunnable(Channel channel) {
		this.channel = channel;
	}

	@Override
	public void run() {
        while (true)
        { 
		 try {
			TimeUnit.SECONDS.sleep(5);
		} catch (InterruptedException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		Jedis fasJedis = null;
		try {
			fasList = new ArrayList<CiosAtsFasInfo>();
			fasJedis = JedisUtilProxy.getJedis();
			for (byte i = 0; i <= 31; i++) {
				CiosAtsFasInfo fasinfo = new CiosAtsFasInfo();
				String statu = fasJedis.hget("SCADA_DATA",
						String.valueOf(i));
				fasinfo.setFasId((byte) (i + 1));
				switch (statu.getBytes()[0]) {
				case 48:
					// 48 对应 0 , modbus 0 对应无火警 , 无火警Ats 对应 2 .
					fasinfo.setStatus(CiosAtsHelper.Down);
					break;
				case 49:
					// 49 对应 1 , modbus 1 对应火警 , ATs火警 为 1
					fasinfo.setStatus(CiosAtsHelper.Fire);
					break;
				default:
					// 其他情况 , ATS 未知 为 0
					fasinfo.setStatus(CiosAtsHelper.UnKnown);
					break;
				}
				// 添加对象
				fasList.add(fasinfo);
			}
		} catch (Exception e) {
			
			logger.info("jedis close fail ...  fasList");

		} finally {
			JedisUtilProxy.close(fasJedis);
		}

		// 从guava中取出basList 并判断是否相同 相同不做操作
		guavaFas = (List<CiosAtsFasInfo>) GuavaCacheUtil.getIfPresent("FAS");
		if (!isListEqual(guavaFas, fasList)) {
			// 如果不相同 , 缓存新的FasList 并调用send方法
			GuavaCacheUtil.put("FAS", fasList);
			sendFasInfo(fasList);
		}
		Jedis ScadaJedis = null;
		try {
			ScadaJedis = JedisUtilProxy.getJedis();
			// SCADA
			scadaList = new ArrayList<CiosAtsScadaInfo>();
			byte count = 1;

			for (byte i = 32; i <= 65; i++) {
				CiosAtsScadaInfo scadaInfo = new CiosAtsScadaInfo();
				String statu = ScadaJedis.hget("SCADA_DATA",
						String.valueOf(i));
				byte[] scadaId = new byte[2];
				scadaId[0] = 0x00;
				scadaId[1] = count;
				scadaInfo.setScadaId(scadaId);
				count += 1;
				switch (statu.getBytes()[0]) {
				case 48:
					// 48 对应 0 , modbus 0 对应无电 , 无电Ats 对应 2 .
					scadaInfo.setStatus(CiosAtsHelper.Down);
					break;
				case 49:
					// 49 对应 1 , modbus 1 对应有电 , ATs有电 为 1
					scadaInfo.setStatus(CiosAtsHelper.Fire);
					break;
				default:
					// 其他情况 , ATS 未知 为 0
					scadaInfo.setStatus(CiosAtsHelper.UnKnown);
					break;
				}
				scadaList.add(scadaInfo);

			}
		} catch (Exception e) {
			
			logger.info("jedis close fail ...  scadaList");

		} finally {
			JedisUtilProxy.close(ScadaJedis);
		}

		// 从guava中取出basList 并判断是否相同 相同不做操作
		guavaScada = (List<CiosAtsScadaInfo>) GuavaCacheUtil
				.getIfPresent("SCADA");
		if (!isListEqual(guavaScada, scadaList)) {
			// 如果不相同 , 缓存新的ScadaList 并调用send方法
			GuavaCacheUtil.put("SCADA", scadaList);
			sendScadaInfo(scadaList);
		}
		Jedis BasJedis = null;
		try {
			BasJedis = JedisUtilProxy.getJedis();
			// BAS
			basList = new ArrayList<CiosAtsBasInfo>();

			String statu = null; //
			int index = 0; // 下标
			CiosAtsBasInfo basInfo = null;
			for (int i = 66; i <= 683; i++) {
				basInfo = new CiosAtsBasInfo();
				// i = 64
				statu = BasJedis.hget("SCADA_DATA", String.valueOf(i));

				// bas_id 两个字节
				basInfo.setBasId(DataUtil.getBasId(BasIdList, index));

				switch (statu.getBytes()[0]) {
				case 48:
					// 48 对应 0 , modbus 0 对应未知 未知跳出判断 执行下一判断
					i += 1; // i = 65

					statu = BasJedis.hget("SCADA_DATA", String.valueOf(i));
					switch (statu.getBytes()[0]) {
					case 48:
						// 48 对应 0 , modbus 0 对应未知 1 对应正转
						basInfo.setDirection(CiosAtsHelper.UnKnown);
						i += 1;
						break;
					case 49:
						// 49 对应 1 , modbus 1 对应反转 , Ats 2 为反转
						basInfo.setDirection(CiosAtsHelper.Down);
						i += 1;
						break;
					default:
						// 其他情况
						basInfo.setDirection(CiosAtsHelper.UnKnown);
						i += 1;
						break;
					}
					break;
				case 49:
					// 49 对应 1 , modbus 1 对应正转 , Ats 1 为正转
					basInfo.setDirection(CiosAtsHelper.Fire);
					// 如果为正转 , 直接+2 判断statu
					i += 2;
					break;
				default:
					// 其他情况
					basInfo.setDirection(CiosAtsHelper.UnKnown);
					i += 2;
					break;
				}

				statu = BasJedis.hget("SCADA_DATA", String.valueOf(i));
				switch (statu.getBytes()[0]) {
				case 48:
					// 48 对应 0 , modbus 0 对应未知 1对应开启 2 对应关闭
					// 当正转反转信息不为0(未知)时 , 风机判定为开启状态
					if (basInfo.getDirection() != 0) {
						basInfo.setStatu(CiosAtsHelper.Fire);
					} else {
						basInfo.setStatu(CiosAtsHelper.UnKnown);
					}
					break;
				case 49:
					// 49 对应 1 , modbus 1 对应停止 , ATS 2 对应 off
					basInfo.setStatu(CiosAtsHelper.Down);
					break;
				default:
					// 48 对应 0 , modbus 0 对应未知 1对应开启 2 对应关闭
					if (basInfo.getDirection() != 0) {
						basInfo.setStatu(CiosAtsHelper.Fire);
					} else {
						basInfo.setStatu(CiosAtsHelper.UnKnown);
					}
					break;
				}
				index += 1;
				basList.add(basInfo);
			}
		} catch (Exception e) {
			
			logger.info("jedis close fail ...  basList");

		} finally {
			JedisUtilProxy.close(BasJedis);
		}

		// 从guava中取出basList 并判断是否相同 相同不做操作
		guavaBas = (List<CiosAtsBasInfo>) GuavaCacheUtil
				.getIfPresent("BAS");
		if (!isListEqual(guavaBas, basList)) {
			// 如果不相同 , 缓存新的BASList 并调用send方法
			GuavaCacheUtil.put("BAS", basList);
			sendBasInfo(basList);
		}
        }
	}



	// 发送火灾信息 (实际)
	public void sendFasInfo(List<CiosAtsFasInfo> list) {

		ByteBuf byteBuf = null;
		byte[] bytes = new byte[list.size() * 2];
		byte count = 0;
		for (int i = 0; i < list.size(); i++) {

			bytes[count] = list.get(i).getFasId();

			count += 1;

			bytes[count] = list.get(i).getStatus();

			count += 1;
		}
		byteBuf = channel.alloc().buffer(count + 9);
		// SystemID
		byteBuf.writeByte(CiosAtsHelper.SystemID);

		// Total Length
		byteBuf.writeByte(0x00);
		byteBuf.writeByte(count + 6); // count + 1(Multi-flag) + 2(Lenth) +
										// 2(Msg_id) + 1 (Number_of_stations)

		// Multi-flag
		byteBuf.writeByte(CiosAtsHelper.MultiFlag);

		// Lenth
		byteBuf.writeByte(0x00);
		byteBuf.writeByte(count + 3); // count = 60 = 30 车站

		// Msg_id
		byteBuf.writeBytes(CiosAtsHelper.FasMsgId);

		// Number_of_stations
		byteBuf.writeByte(count / 2);

		byteBuf.writeBytes(bytes);
		channel.writeAndFlush(byteBuf);
	}

	// 发送牵引分段信息 (实际)
	public void sendScadaInfo(List<CiosAtsScadaInfo> list) {
		ByteBuf byteBuf = null;
		byte[] bytes = new byte[list.size() * 3];
		byte count = 0;
		for (int i = 0; i < list.size(); i++) {
			byte[] scadaId = list.get(i).getScadaId();
			for (int j = 0; j < scadaId.length; j++) {
				bytes[count] = scadaId[j];
				count += 1;
			}

			bytes[count] = list.get(i).getStatus();
			count += 1;

		}
		byteBuf = channel.alloc().buffer(count + 10);
		// SystemID 1
		byteBuf.writeByte(CiosAtsHelper.SystemID);

		// Total Length 2
		byteBuf.writeByte(0x00);
		byteBuf.writeByte(count + 7); // count + 1(Multi-flag) + 2(Lenth) +
										// 2(Msg_id) + 1 (Number_of_stations)

		// Multi-flag 1
		byteBuf.writeByte(CiosAtsHelper.MultiFlag);

		// Lenth
		byteBuf.writeByte(0x00);
		byteBuf.writeByte(count + 4); // count = 60 = 30 车站

		// Msg_id
		byteBuf.writeBytes(CiosAtsHelper.ScadaMsgId);

		// Section number 2 baty
		byteBuf.writeByte(0x00);
		byteBuf.writeByte(count / 3);

		byteBuf.writeBytes(bytes);
		channel.writeAndFlush(byteBuf);

	}

	// 发送隧道风机信息(实际)
	public void sendBasInfo(List<CiosAtsBasInfo> list) {

		ByteBuf byteBuf = null;
		byte[] bytes = new byte[list.size() * 4];
		int count = 0;
		for (int i = 0; i < list.size(); i++) {

			byte[] basId = list.get(i).getBasId();
			for (int j = 0; j < basId.length; j++) {
				bytes[count] = basId[j];

				count += 1;
			}
			bytes[count] = list.get(i).getStatu();
			count += 1;
			bytes[count] = list.get(i).getDirection();
			count += 1;
		}
		System.out.println("count.........." + count);
		byteBuf = channel.alloc().buffer(count + 10);
		// SystemID
		byteBuf.writeByte(CiosAtsHelper.SystemID);

		// Total Length
		byte[] totalLength = DataUtil.short2byte(count + 7);
		byteBuf.writeBytes(totalLength);

		// Multi-flag
		byteBuf.writeByte(CiosAtsHelper.MultiFlag);

		// Lenth
		byte[] length = DataUtil.short2byte(count + 4);
		byteBuf.writeBytes(length);

		// Msg_id
		byteBuf.writeBytes(CiosAtsHelper.BasMsgId);

		// Number_of_stations
		byteBuf.writeByte(0x00);
		byteBuf.writeByte(count / 4);

		byteBuf.writeBytes(bytes);
		channel.writeAndFlush(byteBuf);

	}

	// 比较两个集合是否相同
	/**
	 * 首先进行入参检查防止出现空指针异常 如果两个参数都为空，则返回true 如果有一项为空，则返回false
	 * 接着对第一个list进行遍历，如果某一项第二个list里面没有，则返回false
	 * 还要再将两个list反过来比较，因为可能一个list是两一个list的子集 如果成功遍历结束，返回true
	 * 
	 * @param l0
	 * @param l1
	 * @return
	 */
	public static boolean isListEqual(List l0, List l1) {
		if (l0 == l1)
			return true;
		if (l0 == null && l1 == null)
			return true;
		if (l0 == null || l1 == null)
			return false;
		if (l0.size() != l1.size())
			return false;
		for (Object o : l0) {
			if (!l1.contains(o))
				return false;
		}
		for (Object o : l1) {
			if (!l0.contains(o))
				return false;
		}
		return true;
	}









}
